import { createStore, Commit } from 'vuex'
import axios, { AxiosRequestConfig } from 'axios'
import { arrToObj, objToArr } from './helper'
export interface ResponseType<P> {
  code: number;
  msg: string;
  data: P;
}

export interface ImageProps {
  id?: string;
  url?: string;
  createAt?: string;
  fitUrl?: string;
}

// 用户interface
export interface UserProps {
  isLogin: boolean;
  nickName?: string;
  id?: string;
  column?: string;
  email?: string;
  avatar?: ImageProps;
  description?: string;
}

export interface ColumnProps {
  id: string;
  title: string;
  avatar?: ImageProps;
  description: string;
}

export interface PostProps {
  id: string;
  title: string;
  excerpt?: string;
  content?: string;
  image?: ImageProps | string;
  createdAt?: string;
  column: string;
  author?: string | UserProps;
  isHTML?: boolean;
}

// // async await 封装函数
// const getAndCommit = async (url: string, mutationName: string, commit: Commit) => {
//   const { data } = await axios.get(url)
//   commit(mutationName, data)
//   return data
// }

// // async await 封装函数
// const postAndCommit = async (url: string, mutationName: string, commit: Commit, payload: any) => {
//   const { data } = await axios.post(url, payload)
//   commit(mutationName, data)
//   return data
// }

// async get post delete put
const asyncAndCommit = async (url: string, mutationName: string, commit: Commit, config: AxiosRequestConfig = { method: 'get' }, extraData?: any) => {
  const { data } = await axios(url, config)
  if (extraData) { // post put delete
    commit(mutationName, { data, extraData })
  } else {
    commit(mutationName, data)
  }
  return data
}

interface ListProps<P> {
  [id: string]: P
}

export interface GlobalErrorProps {
  status: boolean;
  message?: string;
}

export interface GlobalDataProps {
  token: string;
  error: GlobalErrorProps;
  loading: boolean;
  columns: { data: ListProps<ColumnProps>; currentPage: number; total: number };
  posts: { data: ListProps<PostProps>; loadedColumns: string[];}
  // posts: { data: ListProps<PostProps>; loadedColumns: ListProps<{total?:number;currentPage?:number}>;} // posts加载更多改造
  user: UserProps;
}

const store = createStore<GlobalDataProps>({
  state: {
    token: localStorage.getItem('token') || '', // 本地会话尝试获取token
    error: { status: false },
    loading: false,
    columns: { data: {}, currentPage: 0, total: 0 }, // isLoaded 是否已加载
    posts: { data: {}, loadedColumns: [] }, // loadedColumns[]存放已加载的数据id,不在异步请求
    user: { isLogin: false }
  },
  mutations: {
    // login (state) {
    //   // ... 新对象替换老对象可以使用对象展开运算符
    //   state.user = { ...state.user, isLogin: true, name: 'viking' }
    // },
    // 创建文章
    createPost (state, newPost) {
      state.posts.data[newPost.id] = newPost
    },
    // 首页文章专栏列表
    fetchColumns (state, rawData) {
      const { data } = state.columns
      const { list, count, currentPage } = rawData.data
      state.columns = {
        data: { ...data, ...arrToObj(list) },
        total: count,
        currentPage: currentPage * 1 // 类型转换
      }
    },
    // column专栏页
    fetchColumn (state, rawData) {
      state.columns.data[rawData.data.id] = rawData.data
    },
    // column专栏页Posts数据  data别名rawData
    fetchPosts (state, { data: rawData, extraData: columnId }) {
      // state.posts.data = arrToObj(rawData.data.list)
      // 以添加方式解决重复异步请求数据的问题而不是原来的直接替换
      state.posts.data = { ...state.posts.data, ...arrToObj(rawData.data.list) }
      state.posts.loadedColumns.push(columnId)
    },
    // 文章详情
    fetchPost (state, rawData) {
      state.posts.data[rawData.data.id] = rawData.data
    },
    // 文章更新   解构
    updatePost (state, { data }) {
      // console.log(data)
      state.posts.data[data.id] = data
    },
    deletePost (state, { data }) {
      // state.posts.data = state.posts.data.filter(post => post.id === data.id)
      delete state.posts.data[data.id]
    },
    // axios加载中loading main.ts提交
    setLoading (state, status) {
      state.loading = status
    },
    // 设置错误提示信息 main.ts提交
    setError (state, e: GlobalErrorProps) {
      state.error = e
    },
    // 获取用户登录信息
    fetchCurrentUser (state, rawData) {
      state.user = { isLogin: true, ...rawData.data }
    },
    // 获取token
    login (state, rawData) {
      const { token } = rawData.data
      state.token = token
      localStorage.setItem('token', token) // 本地会话存储
      axios.defaults.headers.common.Authoriztion = `Bearer ${token}`
    },
    // 退出登录
    logout (state) {
      state.token = ''
      localStorage.removeItem('token')
      delete axios.defaults.headers.common.Authoriztion
    }
  },
  actions: {
    // 首页专栏列表
    fetchColumns ({ state, commit }, params = {}) {
      const { currentPage = 1, pageSize = 6 } = params
      if (state.columns.currentPage < currentPage) {
        return asyncAndCommit(`/api/columns?currentPage=${currentPage}&pageSize=${pageSize}`, 'fetchColumns', commit)
      }
    },
    // fetchColumns (context) {
    //   axios.get('/api/columns').then(resp => {
    //     context.commit('fetchColumns', resp.data)
    //   })
    // },
    // column专栏页
    fetchColumn ({ state, commit }, cid) {
      if (!state.columns.data[cid]) {
        return asyncAndCommit(`/api/columns/${cid}`, 'fetchColumn', commit)
      }
    },
    // column专栏页Posts数据
    fetchPosts ({ state, commit }, cid) {
      if (!state.posts.loadedColumns.includes(cid)) {
        return asyncAndCommit(`/api/columns/${cid}/posts`, 'fetchPosts', commit, { method: 'get' }, cid)
      }
    },
    // 文章详情
    fetchPost ({ state, commit }, id) {
      const currentPost = state.posts.data[id]
      if (!currentPost || !currentPost.content) {
        return asyncAndCommit(`/api/posts/${id}`, 'fetchPost', commit)
      } else {
        // 数据已存在,因为调用这个fetchPost存在.then()所以返回Promise形式
        return Promise.resolve({ data: currentPost })
      }
    },
    // 文章更新
    updatePost ({ commit }, { id, payload }) {
      return asyncAndCommit(`api/posts/${id}`, 'updatePost', commit, {
        method: 'put',
        data: payload
      })
    },
    // 获取用户登录信息 第二步
    fetchCurrentUser ({ commit }) {
      return asyncAndCommit('/api/user/current', 'fetchCurrentUser', commit)
    },
    // 发表文章
    createPost ({ commit }, payload) {
      return asyncAndCommit('/api/posts', 'createPost', commit, { method: 'post', data: payload })
    },
    // 删除文章
    deletePost ({ commit }, id) {
      return asyncAndCommit(`/api/posts/${id}`, 'deletePost', commit, { method: 'delete' })
    },
    // 获取token 第一步
    login ({ commit }, payload) {
      return asyncAndCommit('/api/user/login', 'login', commit, { method: 'post', data: payload })
    },
    // 调用login获取token再调用fetchCurrentUser获取用户登录信息
    loginAndFetch ({ dispatch }, loginData) {
      return dispatch('login', loginData).then(() => {
        return dispatch('fetchCurrentUser')
      })
    }
  },
  // store 的计算属性。就像计算属性一样，getter 的返回值会根据它的依赖被缓存起来，且只有当它的依赖值发生了改变才会被重新计算
  getters: {
    // 首页专栏列表
    getColumns: (state) => {
      return objToArr(state.columns.data)
    },
    // column专栏页
    getColumnById: (state) => (id: string) => {
      // find方法为数组中的每个元素都调用一次函数执行,返回 true 时, find() 返回符合条件的元素，之后的值不会再调用执行函数。
      // return state.columns.find(c => c.id === id)
      return state.columns.data[id]
    },
    // column专栏页Posts数据列表
    getPostsByCid: (state) => (cid: string) => {
      // return state.posts.filter(post => post.column === cid)
      return objToArr(state.posts.data).filter(post => post.column === cid)
    },
    // 获取文章详情
    getCurrentPost: (state) => (id: string) => {
      return state.posts.data[id]
    }
  },
  modules: {
  }
})
export default store
